home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 June: Reference Library / Dev.CD Jun 99 RL Disk 1.toast / What's New / Development Kits / Mac_OS_USB_DDK_v1.2 / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-15  |  12.2 KB  |  371 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17. #include <LowMem.h>
  18.  
  19. #include "MouseModule.h"
  20.  
  21. usbMousePBStruct myMousePB;
  22.  
  23. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  24. {
  25.     paramblock->usbReference = theInterfaceRef;
  26.     paramblock->pbVersion = kUSBCurrentPBVersion;
  27.     
  28.     paramblock->usb.cntl.WIndex = 0;             
  29.     paramblock->usb.cntl.WValue = 0;
  30.     
  31.     paramblock->usbBuffer = nil;        
  32.     paramblock->usbActCount = 0;
  33.     paramblock->usbReqCount = 0;
  34.     paramblock->usbFlags = 0;
  35.     paramblock->usbOther = 0;
  36.     
  37.     paramblock->usbStatus = noErr;
  38. }
  39.  
  40.  
  41.  
  42. Boolean immediateError(OSStatus err)
  43. {
  44.     return((err != kUSBPending) && (err != noErr) );
  45. }
  46.  
  47. void MouseInitiateTransaction(USBPB *pb)
  48. {
  49. register usbMousePBStruct *pMousePB;
  50. OSStatus myErr;
  51.  
  52.     pMousePB = (usbMousePBStruct *)(pb);
  53.     pMousePB->transDepth++;
  54.     if (pMousePB->transDepth < 0)
  55.     {
  56.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  57.     }
  58.     
  59.     if (pMousePB->transDepth > 1)
  60.     {
  61.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  62.     }
  63.     
  64.     if (pMousePB->driverRemovalPending)
  65.     {
  66.         pMousePB->pb.usbRefcon = kReturnFromDriver;
  67.         return;
  68.     }
  69.  
  70.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  71.     {
  72.         case kConfigureInterface:
  73.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  74.             
  75.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  76.             pMousePB->pb.usbRefcon |= kCompletionPending;
  77.             
  78.             myErr = USBConfigureInterface( &pMousePB->pb );
  79.             if(immediateError(myErr))
  80.             {
  81.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr);
  82.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  83.             }
  84.             break;
  85.         
  86.         case kSetProtocol:
  87.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  88.             
  89.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  90.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  91.             pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  92.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  93.             
  94.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  95.             pMousePB->pb.usbRefcon |= kCompletionPending;
  96.         
  97.             myErr = USBDeviceRequest(&pMousePB->pb);
  98.             if (immediateError(myErr))
  99.             {
  100.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr);
  101.             }
  102.             break;
  103.             
  104.         case kSetIdleRequest:
  105.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a SetIdle on non-Apple mice, as some 3rd party mice don't send reports on button up", pMousePB->pipeRef);
  106.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  107.             
  108.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  109.             
  110.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  111.             pMousePB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  112.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  113.             
  114.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  115.             pMousePB->pb.usbRefcon |= kCompletionPending;
  116.  
  117.             myErr = USBDeviceRequest(&pMousePB->pb);
  118.             if(immediateError(myErr))
  119.             {
  120.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr);
  121.             }
  122.             break;
  123.  
  124.         case kFindPipe:
  125.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  126.             
  127.             pMousePB->pb.usbFlags = kUSBIn;
  128.             pMousePB->pb.usbClassType = kUSBInterrupt;
  129.             
  130.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  131.             pMousePB->pb.usbRefcon |= kCompletionPending;
  132.         
  133.             myErr = USBFindNextPipe( &pMousePB->pb );
  134.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  135.             {
  136.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr);
  137.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  138.             }
  139.             break;
  140.         
  141.         case kClearFeature:
  142.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a clear feature on the interrupt endpoint", pMousePB->pipeRef);
  143.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  144.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  145.             
  146.             pMousePB->pb.usb.cntl.BRequest = kUSBRqClearFeature;
  147.             pMousePB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall;
  148.             
  149.             pMousePB->pb.usbFlags = kUSBAddressRequest;                /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */
  150.  
  151.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  152.             pMousePB->pb.usbRefcon |= kCompletionPending;
  153.  
  154.             myErr = USBDeviceRequest(pb);
  155.             if(immediateError(myErr))
  156.             {
  157.                 USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, kMouseModuleName": kClearFeature - immediate error", myErr);
  158.             }
  159.             break;
  160.                 
  161.         case kReadInterruptPipe:
  162.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  163.  
  164.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  165.             pMousePB->pb.usbReqCount = pMousePB->maxPacketSize;
  166.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  167.             
  168.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  169.             pMousePB->pb.usbRefcon |= kCompletionPending;
  170.         
  171.             myErr = USBIntRead(&pMousePB->pb);
  172.             if(immediateError(myErr))
  173.             {
  174.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr);
  175.             }
  176.             break;
  177.             
  178.         default:
  179.             USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  180.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  181.             break;
  182.     }
  183.     
  184. // At this point the control is returned to the system.  If a USB transaction
  185. // has been initiated, then it will call the Complete procs
  186. // (below) to handle the results of the transaction.
  187. }
  188.  
  189.  
  190. void MouseCompletionProc(USBPB *pb)
  191. {
  192. register usbMousePBStruct *pMousePB;
  193. unsigned char    * errstring;
  194. USBPipeState     pipeState;
  195.  
  196.     pMousePB = (usbMousePBStruct *)(pb);
  197.     pMousePB->transDepth--;
  198.     if (pMousePB->transDepth < 0)
  199.     {
  200.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  201.     }
  202.     
  203.     if (pMousePB->transDepth > 1)
  204.     {
  205.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  206.     }
  207.     
  208.     if(pMousePB->pb.usbStatus != noErr)                                                        // was there an error?
  209.     {
  210.         switch(pMousePB->pb.usbRefcon & 0x0fff)                                                // yes, so show where the error occurred
  211.         {
  212.             case kSetProtocol:                    errstring = kMouseModuleName": Error during kSetProtocol"; break;
  213.             case kSetIdleRequest:                  errstring = kMouseModuleName": Error during kSetIdleRequest"; break;
  214.             case kConfigureInterface:            errstring = kMouseModuleName": Error during kConfigureInterface"; break;
  215.             case kFindPipe:                      errstring = kMouseModuleName": Error during kFindPipe"; break;
  216.             case kClearFeature:                  errstring = kMouseModuleName": Error during kClearFeature"; break;
  217.             case kReadInterruptPipe:
  218.                 {
  219.                 errstring = kMouseModuleName": Error during ReadInterruptPipe";
  220.                 LMSetMouseButtonState(0x80);    // release any possibly held-down mouse button
  221.                 break;
  222.                 }
  223.             default:                              errstring = kMouseModuleName": Error occurred, but state is unknown"; break;
  224.         };
  225.         USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & 0x0fff));
  226.         
  227.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  228.         pMousePB->pb.usbRefcon |= kRetryTransaction;
  229.         pMousePB->retryCount--;
  230.         
  231.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest))
  232.         {
  233.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef);
  234.             pMousePB->pb.usbRefcon = kFindPipe;
  235.             pMousePB->pb.usbStatus = noErr;
  236.         }
  237.         else
  238.         {
  239.             if ((!pMousePB->retryCount)    || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  240.             {                                                                                // or received an abort?
  241.                 USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef);
  242.                 pMousePB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  243.                 pMousePB->intPipeAborted = true;    
  244.             }
  245.             else                                                                            // if it didn't abort and there's retries left, then...
  246.             {
  247.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  248.                 {
  249.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  250.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  251.                     {
  252.                         USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  253.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  254.                     }
  255.                 }
  256.             }
  257.         }
  258.     }
  259.     else
  260.     {
  261.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  262.         pMousePB->retryCount = kMouseRetryCount;
  263.     }
  264.  
  265.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  266.     {                                                
  267.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  268.         switch(pMousePB->pb.usbRefcon)
  269.         {
  270.             case kConfigureInterface:
  271.                 pMousePB->pb.usbRefcon = kSetProtocol;
  272.                 break;
  273.                 
  274.             case kSetProtocol:
  275.                 if (kVendorID_AppleComputer == USBToHostWord(pMousePB->deviceDescriptor.vendor) )
  276.                 {
  277.                     pMousePB->pb.usbRefcon = kFindPipe;
  278.                 }
  279.                 else
  280.                 {
  281.                     pMousePB->pb.usbRefcon = kSetIdleRequest;
  282.                 }
  283.                 break;
  284.                 
  285.             case kSetIdleRequest:
  286.                 pMousePB->pb.usbRefcon = kFindPipe;
  287.                 break;
  288.                 
  289.             case kFindPipe:
  290.                 pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue;
  291.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  292.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  293.                 break;
  294.                 
  295.             case kReadInterruptPipe:
  296.                 if (myMousePB.pNotificationRoutine)
  297.                 {
  298.                     (*myMousePB.pNotificationRoutine)(myMousePB.notificationRefcon, pMousePB->pb.usbActCount, (void *)pMousePB->hidReport, myMousePB.interfaceRef);
  299.                 }
  300.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  301.                 break;
  302.  
  303.             default:
  304.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon );
  305.                 pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  306.                 break;
  307.         }
  308.     }
  309.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending))
  310.         MouseInitiateTransaction(pb);
  311. }
  312.  
  313.  
  314. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  315. {
  316. #pragma unused (interfacenum)
  317.  
  318. static Boolean beenThereDoneThat = false;
  319.  
  320.     if(beenThereDoneThat)
  321.     {
  322.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0);
  323.         return;
  324.     }
  325.     beenThereDoneThat = true;
  326.     
  327.     // DebugStr("\pIn Mouse Interface Entry routine");
  328.  
  329.     myMousePB.driverRemovalPending = false;
  330.     myMousePB.intPipeAborted = false;    
  331.  
  332.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  333.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;            
  334.     
  335.     myMousePB.transDepth = 0;                            
  336.     myMousePB.retryCount = kMouseRetryCount;
  337.       
  338.     myMousePB.pSHIMInterruptRoutine = nil;
  339.     myMousePB.pSavedInterruptRoutine = nil;
  340.     
  341.     myMousePB.notificationRefcon = 0;
  342.     myMousePB.pNotificationRoutine = NotifyRegisteredHIDUser;
  343.  
  344.     myMousePB.interfaceRef = theInterfaceRef;        
  345.     myMousePB.pipeRef = nil;        
  346.     
  347.     InitParamBlock(theInterfaceRef, &myMousePB.pb);
  348.     
  349.     myMousePB.pb.usbReference = theInterfaceRef;
  350.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  351.     myMousePB.pb.usbRefcon = kConfigureInterface;        
  352.     
  353.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  354.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  355.     {
  356.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  357.     }
  358.     else
  359.     {
  360.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  361.     }
  362.     
  363.     myMousePB.pCursorDeviceInfo = 0;                
  364.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  365.  
  366.     MouseInitiateTransaction(&myMousePB.pb);
  367. }
  368.  
  369.  
  370.  
  371.